#include "Editor.h"
#include <AntTweakBar.h>
#include "EditorScene.h"
#include "EditorGUI.h"

using namespace irr;
using namespace core;
using namespace video;

Editor* Editor::editor=0;

Editor::Editor(Game* game,PluggableFactory* factory,MapManagerBase* mapManager,IEntity*(*getEntity)(Ogre::SceneNode*))
:game(game),factory(factory),mapManager(mapManager),getEntity(getEntity),selectedEntity(0)
{
	editor=this;
	gui=new EditorGUI(this);
	scene=new EditorScene(this);
	gui->init();
	scene->init();
}

Editor::~Editor()
{
	delete gui;
	delete scene;
}

void Editor::start()
{
	//check if this state is editable
	SGF::IGameState* currentState=game->getCurrentState();
	currentMap=dynamic_cast<SGF::MapState*>(currentState);
	irr::IrrlichtDevice* device=game->getIrrlichtDevice();
	irr::video::IVideoDriver* driver=device->getVideoDriver();

	irr::IEventReceiver* evr=device->getEventReceiver();			
	device->setEventReceiver(this);
	gui->onPreEdit();
	scene->onPreEdit();
	running=true;
	while(device->run()&&running)
	{
		if (device->isWindowActive())
		{
			driver->beginScene();
			scene->render();
			gui->render();
			driver->endScene();
		}
		else
			device->yield();
	}
	if(running)
		game->quit();
	gui->onPostEdit();
	scene->onPostEdit();
	device->setEventReceiver(evr);
}

int translateKey(const irr::SEvent::SKeyInput& input)
{
	int mod=TW_KMOD_NONE;
	if(input.Control)
		mod|=TW_KMOD_CTRL;
	if(input.Shift)
		mod|=TW_KMOD_SHIFT;
#define MAPKEY(key) case key:return TwKeyPressed(TW_##key,mod);
	switch(input.Key)
	{
	case KEY_BACK:return TwKeyPressed(TW_KEY_BACKSPACE,mod);
	case KEY_PRIOR:return TwKeyPressed(TW_KEY_PAGE_UP,mod);		
	case KEY_NEXT:return TwKeyPressed(TW_KEY_PAGE_DOWN,mod);		
    MAPKEY(KEY_TAB)
    MAPKEY(KEY_CLEAR)
    MAPKEY(KEY_RETURN)
    MAPKEY(KEY_PAUSE)
    MAPKEY(KEY_ESCAPE)
    MAPKEY(KEY_DELETE)
    MAPKEY(KEY_UP)
    MAPKEY(KEY_DOWN)
    MAPKEY(KEY_RIGHT)
    MAPKEY(KEY_LEFT)
    MAPKEY(KEY_INSERT)
    MAPKEY(KEY_HOME)
    MAPKEY(KEY_END)
	}
#undef MAPKEY
	return 0;
}

bool Editor::OnEvent(const irr::SEvent& ev)
{
	int handled=0;
	switch(ev.EventType)
	{
	/*case irr::EET_GUI_EVENT:
		guiSignal(ev.GUIEvent);
	break;*/
	case irr::EET_KEY_INPUT_EVENT:
		if((ev.KeyInput.PressedDown))
		{
			if((ev.KeyInput.Char>=32)&&(ev.KeyInput.Char<128))
			{
				char key=static_cast<char>(ev.KeyInput.Char);
				handled=TwKeyPressed(key,0);
			}
			else
				handled=translateKey(ev.KeyInput);
		}
		if(handled) break;
		onKey(ev.KeyInput);
		keySignal(ev.KeyInput);
	break;
	case irr::EET_JOYSTICK_INPUT_EVENT:
		joystickSignal(ev.JoystickEvent);
	break;
	case irr::EET_MOUSE_INPUT_EVENT:
		switch(ev.MouseInput.Event)
		{
		case EMIE_LMOUSE_LEFT_UP:
			handled=TwMouseButton(TW_MOUSE_RELEASED,TW_MOUSE_LEFT);
		break;
		case EMIE_LMOUSE_PRESSED_DOWN:
			handled=TwMouseButton(TW_MOUSE_PRESSED,TW_MOUSE_LEFT);
		break;
		case EMIE_RMOUSE_LEFT_UP:
			handled=TwMouseButton(TW_MOUSE_RELEASED,TW_MOUSE_RIGHT);
		break;
		case EMIE_RMOUSE_PRESSED_DOWN:
			handled=TwMouseButton(TW_MOUSE_PRESSED,TW_MOUSE_RIGHT);
		break;
		case EMIE_MMOUSE_LEFT_UP:
			handled=TwMouseButton(TW_MOUSE_RELEASED,TW_MOUSE_MIDDLE);
		break;
		case EMIE_MMOUSE_PRESSED_DOWN:
			handled=TwMouseButton(TW_MOUSE_PRESSED,TW_MOUSE_MIDDLE);
		break;
		case EMIE_MOUSE_MOVED:
			handled=TwMouseMotion(ev.MouseInput.X,ev.MouseInput.Y);
		break;
		case EMIE_MOUSE_WHEEL:
			{
				static float wheel=0.0f;
				wheel+=ev.MouseInput.Wheel;
				handled=TwMouseWheel((int)wheel);
			}
		break;
		}
		if(handled) break;
		onMouse(ev.MouseInput);
		mouseSignal(ev.MouseInput);
	break;
	case irr::EET_GUI_EVENT:
		{
			std::map<irr::gui::IGUIElement*,boost::function<void(const irr::SEvent&)> >::iterator i=guiCallbacks.find(ev.GUIEvent.Caller);
			if(i!=guiCallbacks.end())
			{
				i->second(ev);
			}
		}
	break;
	}
	return handled!=0;
}

void Editor::onMouse(const irr::SEvent::SMouseInput& ev)
{
	if(ev.Event==EMIE_LMOUSE_PRESSED_DOWN)
	{
		irr::scene::ISceneManager* smgr=game->getIrrlichtDevice()->getSceneManager();
		irr::scene::ISceneCollisionManager* colmgr=smgr->getSceneCollisionManager();
		irr::core::line3df ray=colmgr->getRayFromScreenCoordinates(vector2d<s32>(ev.X,ev.Y));
		scene::ISceneNode* node=colmgr->getSceneNodeFromRayBB(ray,0,true);
		IEntity* entity=getEntity(node);
		if(entity)
		{
			selectEntity(entity);
		}
		if(node)
		{
			core::vector3df size=node->getTransformedBoundingBox().getExtent();
			/*boundingBox->setScale(size);
			boundingBox->setPosition(node->getAbsolutePosition());
			boundingBox->setRotation(node->getRotation());*/
		}
	}
}

void Editor::onKey(const irr::SEvent::SKeyInput& ev)
{
	if(!(ev.PressedDown))
	{
		switch(ev.Key)
		{
		case KEY_F2:
			irr::scene::ICameraSceneNode* camera=game->getIrrlichtDevice()->getSceneManager()->getActiveCamera();
			camera->setInputReceiverEnabled(!camera->isInputReceiverEnabled());
		break;
		}
	}
}

void Editor::selectEntity(SGF::IEntity* entity)
{
	SGF::IEntity* oldEntity=selectedEntity;
	selectedEntity=entity;
	if(oldEntity!=entity)
		newEntitySelected(entity);
}

SGF::IEntity* Editor::getSelectedEntity() const
{
	return selectedEntity;
}

void Editor::bindGUIEvent(irr::gui::IGUIElement* element,boost::function<void(const irr::SEvent&)> callback)
{
	guiCallbacks[element]=callback;
}